<?php

/**
 * Created by PhpStorm.
 * User: superx
 * Date: 14-5-8
 * Time: 下午12:26
 */
abstract class My_BatchMongoDao extends My_BatchDao {

    protected $_connctionName = 'default';
    protected $_databaseName = '';
    protected $_collectionName = '';
    protected $_pk = '_id';

    public function getPK() {
        return $this->_pk;
    }

    /**
     * @return MongoCollection
     */
    public function getTable() {
        return Core_Mongo::getCollection($this->_collectionName, $this->_databaseName, $this->_connctionName);
    }

    public function getConnection() {
        return Core_Mongo::getInstance($this->_connctionName);
    }

    public function getDB() {
        return Core_Mongo::getDB($this->_databaseName, $this->_connctionName);
    }

    /**
     * @param MongoId|integer $pk
     * @return Core_Model|false
     */
    public function findFromDb($pk) {
        if (!$pk) {
            return false;
        }

        /**
         * MongoClient >= 1.5
         */
        if (MongoId::isValid($pk)) {
            if (is_string($pk)) {
                $pk = new MongoId($pk);
            }
            $data = $this->getTable()
                ->findOne(array('_id' => $pk));
        } else {
            $data = $this->getTable()
                ->findOne(array($this->_pk => intval($pk)));
        }

        Core_Log::debug("mongo findOne {$this->_collectionName}: {$pk}", 'debugBatch');

        if ($data) {
            return new $this->_modelClass($data);
        } else {
            return false;
        }
    }

    /**
     * @param                 $data
     * @param MongoId|integer $pk
     * @return bool
     */
    public function update($data, $pk) {
        if (MongoId::isValid($pk)) {
            if (is_string($pk)) {
                $pk = new MongoId($pk);
            }
            $where = ['_id' => $pk];
        } else {
            $where = [$this->_pk => intval($pk)];
        }
        unset($data['_id']);
        $ret = $this->getTable()->update($where, array('$set' => $data));
        if ($ret) {
            $this->clearMemcache($pk);
        }
        return $ret;
    }

    /**
     * @param array $data
     * @param array $condition
     * @return bool
     */
    public function updateWhere(array $data, array $condition) {
        $clear_cache_ids = $this->getTable()->find($condition, [$this->_pk => true]);

        $this->getTable()->update($condition, ['$set' => $data], ['multiple' => true]);

        foreach ($clear_cache_ids as $row) {
            $this->clearMemcache($row[$this->_pk]);
        }
        return true;
    }

    public function insert($data) {
        if ($data instanceof Core_Model) {
            $data = $data->toArray();
        }
        unset($data['_id']);
        $ret = $this->getTable()->insert($data);
        if (!$ret) {
            return false;
        }
        return $data['_id'];
    }

    /**
     * @param $pk
     * @return int
     */
    public function delete($pk) {
//        throw new Exception('do not delete anything');
        if (MongoId::isValid($pk)) {
            if (is_string($pk)) {
                $pk = new MongoId($pk);
            }
            $where = ['_id' => $pk];
        } else {
            $where = [$this->_pk => intval($pk)];
        }

        $ret = $this->getTable()->remove($where);
        if ($ret) {
            $this->clearMemcache($pk);
        }
        return $ret;
    }

    /**
     * @param array $pks
     * @return array
     */
    public function findAllBatch(array $pks) {
        $pks = array_filter($pks);

        $pk_name = $this->_pk;
        foreach ($pks as &$pk) {
            if (MongoId::isValid($pk)) {
                if (is_string($pk)) {
                    $pk = new MongoId($pk);
                }
                $pk_name = '_id';
            }
        }
        $results = $this->getTable()->find(array(
            $pk_name => array(
                '$in' => $pks
            )
        ));

        $ret = array();
        foreach ($results as $row) {
            $k = strval($row[$pk_name]);
            $ret[$k] = new $this->_modelClass($row);
        }

        Core_Log::debug("mongo findAll {$this->_collectionName}", $pks, 'debugBatch');

        return $ret;
    }

    public function insertBatch(array $data) {
        throw new Exception('todo');
    }

    public static function geoNearByCri($lat, $lng, $distance) {
        return array(
            '$near' => array(
                '$geometry' => array(
                    'type' => 'Point',
                    'coordinates' => [floatval($lng), floatval($lat)]
                ),
                '$maxDistance' => intval($distance)
            )
        );
    }

}
